{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 纠缠蒸馏 -- DEJMPS 协议\n",
    "\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "如果读者对纠缠蒸馏的基本概念不熟悉，请浏览我们之前关于 [BBPSSW](./EntanglementDistillation_BBPSSW_CN.ipynb) 的教程。在之前的教程中，我们对纠缠蒸馏的 BBPSSW 协议 [1] 进行了介绍。本教程将介绍 DEJMPS 协议，该协议是由 Deutsch 等人提出的 [2]，和 BBPSSW 协议有着类似的原理。这两种协议最主要的区别是：DEJMPS 协议可以对贝尔对角态（Bell-diagonal state）进行蒸馏，而 BBPSSW 只能保证在 isotropic 态上有效。下面，我们对 DEJMPS 协议进行详细介绍。\n",
    "\n",
    "在纠缠蒸馏中，我们关心的问题是：如何通过 LOCC 操作，从多个含有噪声的纠缠量子比特对中生成一个高保真度的**最大纠缠态（maximally-entangled state）** $|\\Phi^+\\rangle$，也称之为贝尔态。让我们先回顾一下贝尔态的定义，\n",
    "\n",
    "$$ \n",
    "\\begin{align*}\n",
    "|\\Phi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|0\\rangle_B \\pm |1\\rangle_A\\otimes|1\\rangle_B), \\\\\n",
    "|\\Psi^{\\pm}\\rangle_{AB} &= \\frac{1}{\\sqrt{2}}(|0\\rangle_A\\otimes|1\\rangle_B \\pm |1\\rangle_A\\otimes|0\\rangle_B). \n",
    "\\tag{1}\n",
    "\\end{align*}\n",
    "$$\n",
    "\n",
    "$A$ 和 $B$ 代表的是共享纠缠对的双方 Alice 和 Bob。根据贝尔对角态（Bell-digonal state）的定义，在贝尔态作为基底的密度矩阵可以表示为如下对角形式，\n",
    "\n",
    "$$\n",
    "\\rho_{\\text{diag}} = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + p_2 | \\Psi^+\\rangle \\langle \\Psi^+ | + \n",
    "p_3 | \\Phi^-\\rangle \\langle \\Phi^- |  + p_4 | \\Psi^-\\rangle \\langle \\Psi^- |,\n",
    "\\tag{2}\n",
    "$$\n",
    "\n",
    "这里我们假设 $p_1 > p_2 \\geq p_3 \\geq p_4$，并且满足 $p_1 + p_2+ p_3+ p_4 = 1$。那么，我们可以通过以下方式刻画贝尔对角态的纠缠度：\n",
    "\n",
    "* 保真度 (state fidelity)：$F = \\langle \\Phi^+|\\rho_{\\text{diag}}|\\Phi^+\\rangle = p_1$\n",
    "* Negativity： $\\mathcal{N}(\\rho_{\\text{diag}}) = p_1 - 1/2$\n",
    "\n",
    "**提示：** 贝尔对角态仅能在 $p_1 > 1/2$ 时才能通过蒸馏提高保真度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DEJMPS 协议\n",
    "\n",
    "假设 Alice ($A$) 和 Bob ($B$) 持有两对纠缠量子比特，我们分别将它们标记为 $\\{ A_0, B_0 \\}, \\{ A_1, B_1 \\}$。并且这两对量子比特都分别处于相同的贝尔对角态 $\\rho_{diag}$，它们的 $p_1 > 0.5$。那么我们就可以通过如下的流程来蒸馏这两对量子比特，使得输出态和贝尔态 $|\\Phi^+\\rangle$ 之间的保真度更高：\n",
    "\n",
    "1. Alice 和 Bob 先选择任意一对量子比特，**这对量子比特将作为最终的输出比特**。这里假设他们选择了 $A_0$ 和 $B_0$。\n",
    "2. 首先，Alice 对她的两个量子比特施加旋转门 $R_x(\\pi/2)$ ，Bob对他的量子比特施加旋转门 $R_x(-\\pi/2)$。\n",
    "3. 之后，Alice 和 Bob 对他们手中的量子比特施加受控非门（CNOT 门）。这里, $A_0$ 和 $B_0$ 作为控制比特，$A_1$ 和 $B_1$ 作为目标比特。\n",
    "4. 接下来双方分别对 $A_1$ 和 $B_1$ 进行测量，并通过**经典通讯**来交换他们的测量结果 $m_{A_1}, m_{B_1}$。\n",
    "5. 如果Alice和Bob的结果一致（00或11），那么他们可以宣布本次蒸馏过程成功，同时 $A_0$ 和 $B_0$ 作为输出比特，输出态为 $\\rho_{out}$。相反，如果他们的测量结果不一致（01或10），那么本次蒸馏过程失败，丢弃量子比特 $A_0$ 和 $B_0$。\n",
    "\n",
    "<center><img src=\"figures/distillation-fig-DEJMPS.jpg\" height=\"250\" width=\"300\"></center>\n",
    "<div style=\"text-align:center\">图1：DEJMPS 纠缠蒸馏过程电路图 </div>\n",
    "\n",
    "在蒸馏成功的情况下，$A_0$ 和 $B_0$ 作为输出比特，他们的输出态 $\\rho_{out}$ 的和目标态之间的保真度将会提升。输出态的保真度 $F_{out}$ 为\n",
    "\n",
    "$$\n",
    "F_{out} = \\frac{p_1^2 + p_4^2}{(p_1 + p_4)^2 + (p_2 + p_3)^2}.\n",
    "\\tag{3}\n",
    "$$\n",
    "\n",
    "与 BBPSSW 协议相似， DEJMPS 协议并不能保证每次蒸馏都会成功，他的成功率 $p_{succ}$ 是\n",
    "\n",
    "$$ \n",
    "p_{succ} = (p_1 + p_4)^2 + (p_2 + p_3)^2.\n",
    "\\tag{4}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Paddle Quantum 代码实现\n",
    "\n",
    "首先，我们导入相关的包"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-23T09:13:09.766714Z",
     "start_time": "2021-02-23T09:13:07.457788Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from paddle_quantum.locc import LoccNet\n",
    "from paddle import matmul, trace\n",
    "import paddle\n",
    "from paddle_quantum.state import bell_state, isotropic_state, bell_diagonal_state\n",
    "from paddle_quantum.utils import negativity, logarithmic_negativity, is_ppt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在使用量子电路模拟之前，先计算一下对于如下输入态的蒸馏结果的理论值：\n",
    "\n",
    "$$\n",
    "\\rho = p_1 | \\Phi^+\\rangle \\langle \\Phi^+ | + \\frac{1-p_1}{2} | \\Psi^+\\rangle \\langle \\Psi^+ |+ \n",
    "\\frac{1-p_1}{3}| \\Phi^-\\rangle \\langle \\Phi^- |  + \\frac{1-p_1}{6} | \\Psi^-\\rangle \\langle \\Psi^- |.\n",
    "\\tag{5}\n",
    "$$\n",
    "\n",
    "假设我们令 $p_1 = 0.7$，那么保真度的提升以及蒸馏成功的概率可以可以被如下函数计算："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-23T09:13:09.792624Z",
     "start_time": "2021-02-23T09:13:09.769360Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入保真度是: 0.7\n",
      "蒸馏后的保真度的理论值为: 0.7879999999999999\n",
      "蒸馏成功率的理论值为: 0.625\n",
      "输入态是否满足 PPT 条件并因而无法进行蒸馏？ False\n"
     ]
    }
   ],
   "source": [
    "def DEJMPS_metrics(*p):\n",
    "    \"\"\"\n",
    "    返回 DEJMPS 协议蒸馏成功后的保真度以及成功率的理论值.\n",
    "    \"\"\"\n",
    "    F_in = p[0]\n",
    "    p_succ = (p[0] + p[3]) ** 2 + (p[1] + p[2]) ** 2\n",
    "    F_out = (p[0] ** 2 + p[3] ** 2)/p_succ\n",
    " \n",
    "    return F_in, F_out, p_succ\n",
    "\n",
    "p = 0.7\n",
    "F_in, F_out, p_succ = DEJMPS_metrics(p, (1-p)/2, (1-p)/3, (1-p)/6)\n",
    "print(\"输入保真度是:\", F_in)\n",
    "print(\"蒸馏后的保真度的理论值为:\", F_out)\n",
    "print(\"蒸馏成功率的理论值为:\", p_succ)\n",
    "print(\"输入态是否满足 PPT 条件并因而无法进行蒸馏？\", \n",
    "      is_ppt(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "接下来，我们用 Paddle Quantum 中的 LOCCNet 模块创建 DEJMPS 协议对应的电路，并观察他的输出结果："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-23T09:13:11.302009Z",
     "start_time": "2021-02-23T09:13:11.286937Z"
    }
   },
   "outputs": [],
   "source": [
    "class LOCC(LoccNet):\n",
    "    def __init__(self):\n",
    "        super(LOCC, self).__init__()\n",
    "        \n",
    "        # 添加第一个持有者 Alice\n",
    "        # 第一个参数 2 表明该持有者有多少个量子比特\n",
    "        # 第二个参数用来标明该持有者的名字\n",
    "        self.add_new_party(2, party_name='Alice')\n",
    "        \n",
    "        # 添加第二个持有者 Bob\n",
    "        self.add_new_party(2, party_name='Bob')\n",
    "        \n",
    "        # 定义一个贝尔对角态，四个系数对应 p1, p2, p3, p4\n",
    "        _state = paddle.to_tensor(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))\n",
    "        \n",
    "        # ('Alice', 0) 表示 Alice 的第一个量子比特 A0\n",
    "        # ('Bob', 0) 表示 Bob 的第一个量子比特 B0\n",
    "        self.set_init_state(_state, [('Alice', 0), ('Bob', 0)]) \n",
    "        \n",
    "        # ('Alice', 1) 表示 Alice 的第二个量子比特 A1\n",
    "        # ('Bob', 1) 表示 Bob 的第二个量子比特 B1\n",
    "        self.set_init_state(_state, [('Alice', 1), ('Bob', 1)])  \n",
    "        \n",
    "        # 创建两个参数 theta1 和 theta2 用来分别存储 Alice 和 Bob 的本地旋转门的角度\n",
    "        self.theta1 = paddle.to_tensor(np.array([np.pi/2, np.pi/2], dtype='float64'))\n",
    "        self.theta2 = paddle.to_tensor(np.array([-np.pi/2, -np.pi/2], dtype='float64'))\n",
    "        \n",
    "    def DEJMPS(self):\n",
    "        status = self.init_status\n",
    "        \n",
    "        # 用电路模拟 Alice 的本地操作 \n",
    "        cir1 = self.create_ansatz('Alice')\n",
    "        cir1.rx(self.theta1[0], 0)\n",
    "        cir1.rx(self.theta1[1], 1)\n",
    "        cir1.cnot([0, 1])\n",
    "\n",
    "        # 用电路模拟 Bob 的本地操作 \n",
    "        cir2 = self.create_ansatz('Bob')\n",
    "        cir2.rx(self.theta2[0], 0)\n",
    "        cir2.rx(self.theta2[1], 1)\n",
    "        cir2.cnot([0, 1])\n",
    "    \n",
    "        # 运行电路\n",
    "        status = cir1.run(status)\n",
    "        status_mid = cir2.run(status)\n",
    "        \n",
    "        # 参数 ('Alice', 1) 表示测量 Alice 的第二个比特 A1\n",
    "        # 参数 ('Bob', 1) 表示测量 Bob 的第二个比特 B1\n",
    "        # 参数 ['00','11'] 表示我们希望的测量结果\n",
    "        # status_mid 保留了测量得到 '00' 和 '11' 之后的四比特态\n",
    "        status_mid = self.measure(status_mid, [('Alice', 1), ('Bob', 1)], [\"00\", \"11\"])\n",
    "        \n",
    "        # 对 A1&B1 求偏迹，用数组 [('Alice', 0), ('Bob', 0)] 表示想要保留的系统\n",
    "        # status_fin 即为 A0 和 B0 的二比特态\n",
    "        status_fin = self.partial_state(status_mid, [('Alice', 0), ('Bob', 0)])\n",
    "        \n",
    "        return status_fin"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-23T09:13:16.728882Z",
     "start_time": "2021-02-23T09:13:16.547804Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "输入态的保真度为: 0.70000\n",
      "蒸馏后的保真度为: 0.78800\n",
      "蒸馏的成功率为: 62.500%\n",
      "========================================================\n",
      "蒸馏后的态是:\n",
      " [[ 0.45 +0.j  0.   -0.j -0.   +0.j  0.338-0.j]\n",
      " [ 0.   +0.j  0.05 +0.j  0.002-0.j  0.   -0.j]\n",
      " [ 0.   +0.j  0.002+0.j  0.05 -0.j  0.   -0.j]\n",
      " [ 0.338+0.j -0.   -0.j  0.   +0.j  0.45 +0.j]]\n",
      "初始态的 negativity: 0.19999999999999993\n",
      "输出态的 negativity: 0.28800000000000003\n"
     ]
    }
   ],
   "source": [
    "# 运行 DEJMPS 协议\n",
    "status_fin = LOCC().DEJMPS()\n",
    "\n",
    "# 生成我们想要的目标态\n",
    "target_state = paddle.to_tensor(bell_state(2))\n",
    "\n",
    "# 计算他们之间的保真度\n",
    "fidelity = 0\n",
    "for status in status_fin:\n",
    "    fidelity += paddle.real(trace(matmul(target_state, status.state)))\n",
    "fidelity /= len(status_fin)\n",
    "\n",
    "# 计算成功率\n",
    "suc_rate = sum([status.prob for status in status_fin])\n",
    "\n",
    "# 输出结果\n",
    "print(f\"输入态的保真度为: {p:.5f}\")\n",
    "print(f\"蒸馏后的保真度为: {fidelity.numpy()[0]:.5f}\")\n",
    "print(f\"蒸馏的成功率为: {suc_rate.numpy()[0]:#.3%}\")\n",
    "\n",
    "# 输出终态\n",
    "rho_out = status_fin[0].state.numpy()\n",
    "print(\"========================================================\")\n",
    "print(f\"蒸馏后的态是:\\n {np.around(rho_out, 4)}\")\n",
    "print(f\"初始态的 negativity: {negativity(bell_diagonal_state(p, (1-p)/2, (1-p)/3, (1-p)/6))}\")\n",
    "print(f\"输出态的 negativity: {negativity(rho_out)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们可以看到，模拟电路的输出结果和理论预期一致。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 结论\n",
    "\n",
    "DEJMPS 协议可以高效地从两对含有噪声的纠缠量子对中蒸馏出一对具有更高保真度的纠缠对。和只能蒸馏 isotropic 态的 BBPSSW 协议相比，DEJMPS 协议可以应用在任意贝尔对角态上。因为贝尔对角态本身包含了 isotropic 态，所以 DEJMPS 协议是一种比 BBPSSW 协议更通用的蒸馏协议。然而，他也和 BBPSSW 协议具有相同的缺点：仍然不能对任意输入态进行蒸馏，并且在多对量子比特的场景下没有良好的拓展性。\n",
    "\n",
    "我们建议感兴趣的读者可以接着浏览以下教程学习 [如何通过 LOCCNet 设计全新的纠缠蒸馏方案](./EntanglementDistillation_LOCCNET_CN.ipynb)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 参考资料\n",
    "\n",
    "[1] Bennett, Charles H., et al. \"Purification of noisy entanglement and faithful teleportation via noisy channels.\" [Physical Review Letters 76.5 (1996): 722.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.76.722)\n",
    "\n",
    "[2] Deutsch, David, et al. \"Quantum privacy amplification and the security of quantum cryptography over noisy channels.\" [Physical Review Letters 77.13 (1996): 2818.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.77.2818)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
